package grimbo.goodwinfooty.server.mvc;

import grimbo.goodwinfooty.server.ByteUtils;
import grimbo.goodwinfooty.server.FootyMatrixLoader;
import grimbo.goodwinfooty.server.GoodwinFootyDB;
import grimbo.goodwinfooty.service.model.FootyMatrix;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

/**
 * Uploads an xls file and stores as a FootyMatrix object.
 */
public class UploadXLSController extends AbstractController {
	private static final String CNAME = UploadXLSController.class.getName();
	private static final Logger log = Logger.getLogger(CNAME);
	private static final String UPLOAD_XLS_FILE_PARAM = "xls-file";

	private GoodwinFootyDB datastore;

	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest req,
			HttpServletResponse res) throws Exception {
		if ("GET".equals(req.getMethod())) {
			return handleGet(req, res);
		}
		return handlePost(req, res);
	}

	protected ModelAndView handleGet(HttpServletRequest req,
			HttpServletResponse res) throws Exception {
		return new ModelAndView("upload-xls");
	}

	protected ModelAndView handlePost(HttpServletRequest req,
			HttpServletResponse res) throws Exception {
		res.setContentType("text/plain");
		FootyMatrix fm = null;
		try {
			fm = createFootyMatrix(req);
		} catch (FileUploadException e) {
			throw new IOException(e);
		}
		datastore.saveFootyMatrix(fm);
		res.getWriter().println(fm);
		return null;
	}

	private FootyMatrix createFootyMatrix(HttpServletRequest req)
			throws FileUploadException, IOException {
		byte[] xlsFile = getXlsFileBytes(req);
		return createFootyMatrix(xlsFile);
	}

	private FootyMatrix createFootyMatrix(byte[] xlsFile) throws IOException {
		try {
			FootyMatrixLoader loader = new FootyMatrixLoader();
			return loader.loadAsFootyMatrix(new ByteArrayInputStream(xlsFile));
		} catch (Exception e) {
			throw new IOException(e);
		}
	}

	private byte[] getXlsFileBytes(HttpServletRequest req)
			throws FileUploadException, IOException {
		final String MNAME = "getXlsFileBytes(HttpServletRequest)";
		final boolean DEBUG = log.isLoggable(Level.FINE);

		UploadHelper helper = new UploadHelper();

		MyFileItemStreamHandler myFileItemStreamHandler = new MyFileItemStreamHandler(
				UPLOAD_XLS_FILE_PARAM);
		helper.handleRequest(req, myFileItemStreamHandler);

		return myFileItemStreamHandler.fileBytes;
	}

	public GoodwinFootyDB getDatastore() {
		return datastore;
	}

	public void setDatastore(GoodwinFootyDB datastore) {
		this.datastore = datastore;
	}

	/**
	 * My callback.
	 */
	static class MyFileItemStreamHandler implements FileItemStreamHandler {
		private String fileParam;
		private byte[] fileBytes;

		MyFileItemStreamHandler(String fileParam) {
			if ((null == fileParam) || ("".equals(fileParam.trim()))) {
				throw new IllegalArgumentException(
						"fileParam cannot be null or blank");
			}
			this.fileParam = fileParam;
		}

		@Override
		public void handleFileItemStream(FileItemStream item)
				throws IOException {
			String name = item.getFieldName();
			if (!name.equals(fileParam)) {
				return;
			}

			if (!item.isFormField()) {
				InputStream in = item.openStream();
				fileBytes = ByteUtils.readStream(in);
			}
		}
	}
}
